/*
 *   Copyright 1999-2018 dragonshard.net.
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *        http://www.apache.org/licenses/LICENSE-2.0
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

package net.dragonshard.dsf.data.mybatis.framework.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.additional.query.impl.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.additional.query.impl.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.additional.update.impl.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.additional.update.impl.UpdateChainWrapper;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * Copy on com.baomidou.mybatisplus.extension.service.IService
 **/
public interface IDsfService<T> {

  /**
   * 插入一条记录（选择字段，策略插入）
   *
   * @param entity 实体对象
   */
  boolean save(T entity);

  /**
   * 插入（批量）
   *
   * @param entityList 实体对象集合
   */
  default boolean saveBatch(Collection<T> entityList) {
    return saveBatch(entityList, 1000);
  }

  /**
   * 插入（批量）
   *
   * @param entityList 实体对象集合
   * @param batchSize 插入批次数量
   */
  boolean saveBatch(Collection<T> entityList, int batchSize);

  /**
   * 批量修改插入
   *
   * @param entityList 实体对象集合
   */
  default boolean saveOrUpdateBatch(Collection<T> entityList) {
    return saveOrUpdateBatch(entityList, 1000);
  }

  /**
   * 批量修改插入
   *
   * @param entityList 实体对象集合
   * @param batchSize 每次的数量
   */
  boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);

  /**
   * 根据 ID 删除
   *
   * @param id 主键ID
   */
  boolean removeById(Serializable id);

  /**
   * 根据 columnMap 条件，删除记录
   *
   * @param columnMap 表字段 map 对象
   */
  boolean removeByMap(Map<String, Object> columnMap);

  /**
   * 根据 entity 条件，删除记录
   *
   * @param queryWrapper 实体包装类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
   */
  boolean remove(Wrapper<T> queryWrapper);

  /**
   * 删除（根据ID 批量删除）
   *
   * @param idList 主键ID列表
   */
  boolean removeByIds(Collection<? extends Serializable> idList);

  /**
   * 根据 ID 选择修改
   *
   * @param entity 实体对象
   */
  boolean updateById(T entity);

  /**
   * 根据 whereEntity 条件，更新记录
   *
   * @param entity 实体对象
   * @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
   */
  boolean update(T entity, Wrapper<T> updateWrapper);

  /**
   * 根据 UpdateWrapper 条件，更新记录 需要设置sqlset
   *
   * @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
   */
  default boolean update(Wrapper<T> updateWrapper) {
    return update(null, updateWrapper);
  }

  /**
   * 根据ID 批量更新
   *
   * @param entityList 实体对象集合
   */
  default boolean updateBatchById(Collection<T> entityList) {
    return updateBatchById(entityList, 1000);
  }

  /**
   * 根据ID 批量更新
   *
   * @param entityList 实体对象集合
   * @param batchSize 更新批次数量
   */
  boolean updateBatchById(Collection<T> entityList, int batchSize);

  /**
   * TableId 注解存在更新记录，否插入一条记录
   *
   * @param entity 实体对象
   */
  boolean saveOrUpdate(T entity);

  /**
   * 根据 ID 查询
   *
   * @param id 主键ID
   */
  T getById(Serializable id);

  /**
   * 查询（根据ID 批量查询）
   *
   * @param idList 主键ID列表
   */
  Collection<T> listByIds(Collection<? extends Serializable> idList);

  /**
   * 查询（根据 columnMap 条件）
   *
   * @param columnMap 表字段 map 对象
   */
  Collection<T> listByMap(Map<String, Object> columnMap);

  /**
   * 根据 Wrapper，查询一条记录 <br/>
   * <p>结果集，如果是多个会抛出异常，随机取一条加上限制条件 wrapper.last("LIMIT 1")</p>
   *
   * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
   */
  default T getOne(Wrapper<T> queryWrapper) {
    return getOne(queryWrapper, true);
  }

  /**
   * 根据 Wrapper，查询一条记录
   *
   * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
   * @param throwEx 有多个 result 是否抛出异常
   */
  T getOne(Wrapper<T> queryWrapper, boolean throwEx);

  /**
   * 根据 Wrapper，查询一条记录
   *
   * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
   */
  Map<String, Object> getMap(Wrapper<T> queryWrapper);

  /**
   * 根据 Wrapper，查询一条记录
   *
   * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
   * @param mapper 转换函数
   */
  <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

  /**
   * 根据 Wrapper 条件，查询总记录数
   *
   * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
   */
  int count(Wrapper<T> queryWrapper);

  /**
   * 查询总记录数
   *
   * @see Wrappers#emptyWrapper()
   */
  default int count() {
    return count(Wrappers.emptyWrapper());
  }

  /**
   * 查询列表
   *
   * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
   */
  List<T> list(Wrapper<T> queryWrapper);

  /**
   * 查询所有
   *
   * @see Wrappers#emptyWrapper()
   */
  default List<T> list() {
    return list(Wrappers.emptyWrapper());
  }

  /**
   * 翻页查询
   *
   * @param page 翻页对象
   * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
   */
  IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);

  /**
   * 无条件翻页查询
   *
   * @param page 翻页对象
   * @see Wrappers#emptyWrapper()
   */
  default IPage<T> page(IPage<T> page) {
    return page(page, Wrappers.emptyWrapper());
  }

  /**
   * 查询列表
   *
   * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
   */
  List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);

  /**
   * 查询所有列表
   *
   * @see Wrappers#emptyWrapper()
   */
  default List<Map<String, Object>> listMaps() {
    return listMaps(Wrappers.emptyWrapper());
  }

  /**
   * 查询全部记录
   */
  default List<Object> listObjs() {
    return listObjs(Function.identity());
  }

  /**
   * 查询全部记录
   *
   * @param mapper 转换函数
   */
  default <V> List<V> listObjs(Function<? super Object, V> mapper) {
    return listObjs(Wrappers.emptyWrapper(), mapper);
  }

  /**
   * 根据 Wrapper 条件，查询全部记录
   *
   * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
   */
  default List<Object> listObjs(Wrapper<T> queryWrapper) {
    return listObjs(queryWrapper, Function.identity());
  }

  /**
   * 根据 Wrapper 条件，查询全部记录
   *
   * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
   * @param mapper 转换函数
   */
  <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

  /**
   * 翻页查询
   *
   * @param page 翻页对象
   * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
   */
  IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);

  /**
   * 无条件翻页查询
   *
   * @param page 翻页对象
   * @see Wrappers#emptyWrapper()
   */
  default IPage<Map<String, Object>> pageMaps(IPage<T> page) {
    return pageMaps(page, Wrappers.emptyWrapper());
  }

  /**
   * 获取对应 entity 的 BaseMapper
   *
   * @return BaseMapper
   */
  BaseMapper<T> getBaseMapper();

  /**
   * 以下的方法使用介绍:
   *
   * 一. 名称介绍
   * 1. 方法名带有 query 的为对数据的查询操作, 方法名带有 update 的为对数据的修改操作
   * 2. 方法名带有 lambda 的为内部方法入参 column 支持函数式的
   *
   * 二. 支持介绍
   * 1. 方法名带有 query 的支持以 {@link ChainQuery} 内部的方法名结尾进行数据查询操作
   * 2. 方法名带有 update 的支持以 {@link ChainUpdate} 内部的方法名为结尾进行数据修改操作
   *
   * 三. 使用示例,只用不带 lambda 的方法各展示一个例子,其他类推
   * 1. 根据条件获取一条数据: `query().eq("column", value).one()`
   * 2. 根据条件删除一条数据: `update().eq("column", value).remove()`
   *
   */

  /**
   * 链式查询 普通
   *
   * @return QueryWrapper 的包装类
   */
  default QueryChainWrapper<T> query() {
    return new QueryChainWrapper<>(getBaseMapper());
  }

  /**
   * 链式查询 lambda 式
   * <p>注意：不支持 Kotlin </p>
   *
   * @return LambdaQueryWrapper 的包装类
   */
  default LambdaQueryChainWrapper<T> lambdaQuery() {
    return new LambdaQueryChainWrapper<>(getBaseMapper());
  }

  /**
   * 链式更改 普通
   *
   * @return UpdateWrapper 的包装类
   */
  default UpdateChainWrapper<T> update() {
    return new UpdateChainWrapper<>(getBaseMapper());
  }

  /**
   * 链式更改 lambda 式
   * <p>注意：不支持 Kotlin </p>
   *
   * @return LambdaUpdateWrapper 的包装类
   */
  default LambdaUpdateChainWrapper<T> lambdaUpdate() {
    return new LambdaUpdateChainWrapper<>(getBaseMapper());
  }
}
